package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.service.UserPaidTrackService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Autowired
	private WxMaService wxMaService;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private KafkaService kafkaService;

	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;

	@Autowired
	private UserPaidAlbumMapper userPaidAlbumMapper;

	@Autowired
	private AlbumFeignClient albumFeignClient;

	@Autowired
	private UserVipServiceMapper userVipServiceMapper;

	@Autowired
	private VipServiceConfigMapper vipServiceConfigMapper;

	/**
	 * 微信小程序登录，将微信账户openId根本地用户关联，返回自定义登录状态（token令牌）
	 * @param code 小程序端提交临时凭证，用户服务器端获取微信（token 令牌）
	 * @return
	 */
	@Override
	public Map<String, String> wxLogin(String code) {
		try {
			// 1.获取当前登录微信账户唯一标识：wxOpenId
			WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
			String openid = sessionInfo.getOpenid();

			// 2.判断当前微信是否是首次登录小程序
			LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(UserInfo::getWxOpenId,openid);
			UserInfo userInfo = userInfoMapper.selectOne(lambdaQueryWrapper);

			// 3.初次登录，初始化账单记录（余额）
			if (userInfo == null){
				// 3.1 保存用户记录 将微信openID关联自定义用户
				userInfo = new UserInfo();
				userInfo.setWxOpenId(openid);
				userInfo.setNickname("听友" + IdUtil.getSnowflakeNextId());
				userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
				userInfo.setIsVip(0);
				userInfo.setVipExpireTime(null);
				userInfoMapper.insert(userInfo);
				// 3.2 发送Kafka消息 消息：用户ID
				kafkaService.sendKafkaMessage(KafkaConstant.QUEUE_USER_REGISTER,userInfo.getId().toString());

			}
			// 4.产生登录令牌基于用户信息根token进行关联
			 // 4.1生成自定义token
			String token = IdUtil.randomUUID();
			// 4.2构建登录key
			String tokenKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
			 // 4.3将token构建的Key写入redis，将用户信息UserInfoVo作为Value
			UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
			redisTemplate.opsForValue().set(tokenKey,userInfoVo,RedisConstant.USER_LOGIN_REFRESH_KEY_TIMEOUT, TimeUnit.SECONDS);
			// 5.封装登录结果
			Map<String,String> map = new HashMap<>();
			map.put("token",token);
			return map;
		} catch (WxErrorException e) {
			log.error("[用户服务]微信登录异常：{}", e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 获取登录用户信息
	 * @param userId
	 * @return
	 */
	@Override
	public UserInfoVo getUserInfo(Long userId) {
		// 1.根据主键id查询用户对象
		UserInfo userInfo = userInfoMapper.selectById(userId);
		Assert.notNull(userInfo,"当前用户不存在");
		// 2.将用户PO转为VO
		UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
		return userInfoVo;
	}


	/**
	 * 更新用户信息
	 * @param userInfoVo
	 */
	@Override
	public void updateUser(UserInfoVo userInfoVo) {
		// 1.获取用戶id
		Long userId = AuthContextHolder.getUserId();
		// 2.对象赋值
		UserInfo userInfo = new UserInfo();
		userInfo.setId(userId);
		userInfo.setNickname(userInfoVo.getNickname());
		userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
		userInfoMapper.updateById(userInfo);
	}

	/**
	 *	提供给专辑服务动态判断声音付费标识业务接口，其中请求体参数声音ID集合，每一页中声音ID都需要提交来进行验证购买情况
	 * @param userId  用户ID
	 * @param albumId 专辑ID
	 * @param needCheckTrackList 待检查购买情况声音ID集合
	 * @return {专辑ID：购买结果} 1：已购买 0：未购买
	 */
	@Override
	public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckTrackList) {
		HashMap<Long,Integer> map = new HashMap<>();
		// 1. 优先根据专辑ID判断是否购买过专辑，如果已购专辑，待检查声音ID购买情况全部设置1返回
		LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>();
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId,albumId);
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId,userId);
		Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);
		if (count > 0){
			// 说明该专辑已购买
			for (Long paidTrackId : needCheckTrackList) {
				map.put(paidTrackId,1);
			}
			return map;
		}
		// 2. 根据专辑ID+用户ID查询已购声音记录，得到已购声音集合
		LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
		userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId,userId);
		userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId,albumId);
		userPaidTrackLambdaQueryWrapper.select(UserPaidTrack::getTrackId);
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);
		// 3. 如果已购声音ID为空，将待检查声音ID购买情况全部设置0返回
		if (CollectionUtil.isEmpty(userPaidTrackList)){
			// 说明该用户未购买声音
			for (Long noPaidTrack : needCheckTrackList) {
				map.put(noPaidTrack,0);
			}
			return map;
		}
		// 4. 存在已购买声音，找出已购买过声音ID将已购买情况全部设置1 反之设置为0
		// 4.1 从已购声音集合中获取已购声音ID集合
		List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
		// 4.2 循环待检测购买情况声音ID集合，如果检测声音ID包含在已购声音ID集合中 手动将购买情况设置为1 ，反之设置为0
		for (Long needCheckPayTrackId : needCheckTrackList) {
			if (userPaidTrackIdList.contains(needCheckPayTrackId)){
				map.put(needCheckPayTrackId,1);
			}else {
				map.put(needCheckPayTrackId,0);
			}
		}
		return map;
	}

	/**
	 * 根据专辑ID判断用户是否买过该专辑
	 * @param albumId
	 * @return
	 */
	@Override
	public Boolean isPaidAlbum(Long albumId) {
		// 1. 获取用户Id
		Long userId = AuthContextHolder.getUserId();

		// 2.用户ID+专辑ID查询是否存在购买记录
		LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidAlbum::getAlbumId,albumId);
		queryWrapper.eq(UserPaidAlbum::getUserId,userId);
		Long count = userPaidAlbumMapper.selectCount(queryWrapper);

		return count > 0;
	}

	/**
	 * 根据专辑id+用户ID获取用户已购买声音id列表
	 * @param albumId
	 * @return
	 */
	@Override
	public List<Long> getUserPaidTrackList(Long albumId) {
		// 1.获取当前用户ID
		Long userId = AuthContextHolder.getUserId();

		// 2.根据专辑id+用户ID获取用户已购买声音列表
		LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidTrack::getUserId,userId);
		queryWrapper.eq(UserPaidTrack::getAlbumId,albumId);
		queryWrapper.select(UserPaidTrack::getTrackId);
		List<UserPaidTrack> userPaidTracks = userPaidTrackMapper.selectList(queryWrapper);

		// 3.获取已购买声音ID列表
		if (CollectionUtil.isNotEmpty(userPaidTracks)){
			List<Long> userPaidTrackIdList = userPaidTracks.stream()
					.map(UserPaidTrack::getTrackId).collect(Collectors.toList());
			return userPaidTrackIdList;
		}
		return null;
	}

	/**
	 * 提交订单支付（余额，支付宝）成功-虚拟物品发货
	 * @param userPaidRecordVo 订单编号 用户ID 购买项目类型 1001-专辑 1002-声音 1003-vip会员 项目ID集合
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
		// 1. 判断商品类型
		if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)){
			//  2.新增专辑购买记录
			// 2.1 根据订单编号查询已购专辑记录 如果购买记录存在说明已经保存过则忽略
			LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>();
			userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getOrderNo,userPaidRecordVo.getOrderNo());
			userPaidAlbumLambdaQueryWrapper.last("limit 1");
			Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);
			if (count > 0){
				return;
			}
			// 2.2 新增专辑购买记录
			UserPaidAlbum userPaidAlbum = new UserPaidAlbum();
			userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
			userPaidAlbum.setUserId(userPaidAlbum.getUserId());
			userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
			userPaidAlbumMapper.insert(userPaidAlbum);

		}else if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)){
			// 3. 新增声音购买记录
			// 3.1 根据订单编号查询已购声音记录 如果购买记录存在说明已经保存过则忽略
			LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
			userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getOrderNo,userPaidRecordVo.getOrderNo());
			userPaidTrackLambdaQueryWrapper.last("limit 1");
			Long count = userPaidTrackMapper.selectCount(userPaidTrackLambdaQueryWrapper);
			if (count > 0){
				return;
			}
			// 3.2 调用专辑服务得到声音信息，通过声音信息拿到专辑ID
			TrackInfo trackInfo = albumFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0)).getData();
			// 3.3 遍历购买声音ID集合
			userPaidRecordVo.getItemIdList()
					.stream().forEach(trackId -> {
						UserPaidTrack userPaidTrack = new UserPaidTrack();
						userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
						userPaidTrack.setUserId(userPaidRecordVo.getUserId());
						userPaidTrack.setAlbumId(trackInfo.getAlbumId());
						userPaidTrack.setTrackId(trackId);
						userPaidTrackMapper.insert(userPaidTrack);
					});

		}else if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_VIP)){
			// 4. 新增会员购买记录
			// 4.1 根据订单编号查询已购会员记录是否存在
			LambdaQueryWrapper<UserVipService> userVipServiceLambdaQueryWrapper = new LambdaQueryWrapper<>();
			userVipServiceLambdaQueryWrapper.eq(UserVipService::getOrderNo,userPaidRecordVo.getOrderNo());
			userVipServiceLambdaQueryWrapper.last("limit 1");
			Long count = userVipServiceMapper.selectCount(userVipServiceLambdaQueryWrapper);
			if (count > 0){
				return;
			}
			// 4.2 根据购买套餐ID查询套餐信息-得到会员服务月数用于计算过期时间
			VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(userPaidRecordVo.getItemIdList().get(0));
			Integer serviceMonth = vipServiceConfig.getServiceMonth();
			// 4.3 判断用户会员新开或者会员续费
			UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
			UserVipService userVipService = new UserVipService();
			int isVip = userInfo.getIsVip().intValue();
			// 4.4 新增会员购买记录
			if (isVip == 1 && userInfo.getVipExpireTime().after(new Date())){
				// 是会员，在过期时间的基础上续费
				userVipService.setStartTime(userInfo.getVipExpireTime());
				// hutool工具包 月份偏移量
				userVipService.setExpireTime(DateUtil.offsetMonth(userInfo.getVipExpireTime(),serviceMonth));
			}else {
				userVipService.setStartTime(new Date());
				userVipService.setExpireTime(DateUtil.offsetMonth(new Date(),serviceMonth));
			}
			userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
			userVipService.setUserId(userPaidRecordVo.getUserId());
			userVipServiceMapper.insert(userVipService);
			// 4.5 更新会员标识以及延长会员过期时间
			userInfo.setIsVip(1);
			userInfo.setVipExpireTime(userVipService.getExpireTime());
			userInfoMapper.updateById(userInfo);
		}
	}
}
